#include "messageshowarea.h"
#include "model/data.h"
#include "debug.h"
#include "mainwidget.h"
#include "userinfowidget.h"

#include <QScrollBar>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QFontMetrics>
#include <QPainter>
#include <QStyleOption>
#include <QPainterPath>
#include <QTimer>

MessageShowArea::MessageShowArea()
{
    QVBoxLayout *layout = new QVBoxLayout();
    layout->setSpacing(0);
    layout->setContentsMargins(0, 0, 0, 0);

    container = new QWidget();
    container->setLayout(layout);

    // 初始化基本属性
    this->setWidget(container);
    this->setWidgetResizable(true);
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    QString vScrollBarStyle = "QScrollBar:vertical { width : 5px; background : none; border : none; margin : 0 px; }";
    vScrollBarStyle += "QScrollBar::handle:vertical { background: #c0c0c0; min-height: 20px; border-radius: 5px; }";
    vScrollBarStyle += "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0px; }";
    vScrollBarStyle += "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; }";
    this->verticalScrollBar()->setStyleSheet(vScrollBarStyle);
    QString hScrollBarStyle = "QScrollBar:horizontal { height : 0px; }";
    this->verticalScrollBar()->setAttribute(Qt::WA_OpaquePaintEvent, false);
    this->horizontalScrollBar()->setStyleSheet(hScrollBarStyle);
    // QString style = "QScrollArea { border-bottom : 1px solid rgb(230, 230, 230); border-left : 1px solid rgb(230, 230, 230); }";
    // this->setStyleSheet(style);

// 添加 "构造测试数据" 逻辑.
#if TEST_UI
    model::UserInfo userInfo;
    userInfo.userId = QString::number(1000);
    userInfo.nickname = "张三";
    userInfo.description = "从今天开始认真敲代码";
    userInfo.avatar = QIcon(":/resource/image/defaultAvatar.png");
    userInfo.phone = "18612345678";
    model::Message message = model::Message::makeMessage(model::MessageType::TEXT_TYPE, "", userInfo, QString("这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息").toUtf8(), "");
    this->addMessage(false, message);

    for (int i = 1; i <= 30; ++i) {
        model::UserInfo userInfo;
        userInfo.userId = QString::number(1000 + i);
        userInfo.nickname = "张三" + QString::number(i);
        userInfo.description = "从今天开始认真敲代码";
        userInfo.avatar = QIcon(":/resource/image/defaultAvatar.png");
        userInfo.phone = "18612345678";
        model::Message message = model::Message::makeMessage(model::MessageType::TEXT_TYPE, "", userInfo, (QString("这是一条测试消息") + QString::number(i)).toUtf8(), "");
        this->addMessage(true, message);
    }
#endif
}

///
/// \brief MessageShowArea::addMessage 在消息展示区尾插一条消息
/// \param isLeft 消息是否是左侧消息
/// \param message 消息对象
///
void MessageShowArea::addMessage(bool isLeft, const model::Message &message)
{
    MessageItem* messageItem = MessageItem::makeMessageItem(isLeft, message);
    container->layout()->addWidget(messageItem);

    // 强制更新布局，确保新部件几何尺寸被计算
    container->layout()->activate();
    // 使用单次定时器，确保滚动操作在布局计算完成后执行
    QTimer::singleShot(0, this, [this, messageItem]() {
        this->ensureWidgetVisible(messageItem);
    });
}

///
/// \brief MessageShowArea::addFontMessage 在消息展示区头插一条消息
/// \param isLeft 消息是否是左侧消息
/// \param message 消息对象
///
void MessageShowArea::addFontMessage(bool isLeft, const model::Message &message)
{
    MessageItem* messageItem = MessageItem::makeMessageItem(isLeft, message);
    QVBoxLayout* layout = dynamic_cast<QVBoxLayout*>(container->layout());
    layout->insertWidget(0, messageItem);
}

void MessageShowArea::clear()
{
    // 遍历布局管理器, 删除里面的元素
    QLayout* layout = container->layout();
    for (int i = layout->count() - 1; i >= 0; --i) {
        QLayoutItem* item = layout->takeAt(i);
        if (item != nullptr && item->widget() != nullptr) {
            delete item->widget();
        }
    }
}

MessageItem::MessageItem(bool isLeft)
    : isLeft(isLeft)
{

}

MessageItem *MessageItem::makeMessageItem(bool isLeft, const model::Message &message)
{
    // 消息的头像
    QPushButton *avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(QSize(40, 40));
    avatarBtn->setIconSize(QSize(40, 40));
    avatarBtn->setIcon(message.sender.avatar);

    // 消息的发送人名称和发送时间
    QLabel *nameLabel = new QLabel();
    nameLabel->setText(message.sender.nickname + " | " + message.time);
    nameLabel->setAlignment(Qt::AlignBottom);
    QString nameLabelStyle = "QLabel { font-size : 12px; color : rgb(178, 178, 178); }";
    nameLabel->setStyleSheet(nameLabelStyle);

    // 消息体对象
    QWidget *contentWidget = nullptr;
    switch(message.messageType) {
    case model::TEXT_TYPE:
        contentWidget = makeTextMessageItem(isLeft, message.content);
        break;
    case model::IMAGE_TYPE:
        contentWidget = makeImageMessageItem();
        break;
    case model::FILE_TYPE:
        contentWidget = makeFileMessageItem();
        break;
    case model::SPEECH_TYPE:
        contentWidget = makeSpeechMessageItem();
        break;
    default:
        LOG() << "未知消息类型！messageType=" << message.messageType;
        break;
    }

    // 组织控件的网格布局管理器
    QGridLayout *layout = new QGridLayout();
    layout->setSpacing(10);
    layout->setContentsMargins(30, 10, 30, 10);
    if (isLeft) {
        layout->addWidget(avatarBtn, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft);
        layout->addWidget(nameLabel, 0, 1, 1, 1, Qt::AlignTop | Qt::AlignLeft);
        layout->addWidget(contentWidget, 1, 1, 1, 1);
    } else {
        layout->addWidget(avatarBtn, 0, 1, 2, 1, Qt::AlignTop | Qt::AlignRight);
        layout->addWidget(nameLabel, 0, 0, 1, 1, Qt::AlignTop | Qt::AlignRight);
        layout->addWidget(contentWidget, 1, 0, 1, 1);
    }

    MessageItem *messageItem = new MessageItem(isLeft);
    messageItem->setMinimumHeight(100);
    messageItem->setLayout(layout);


    // 连接信号槽，处理用户点击头像的操作
    connect(avatarBtn, &QPushButton::clicked, messageItem, [=](){
        MainWidget* mainWidget = MainWidget::getInstance();
        UserInfoWidget* userInfoWidget = new UserInfoWidget(message.sender, mainWidget);
        userInfoWidget->exec();
    });


    return messageItem;
}

QWidget *MessageItem::makeTextMessageItem(bool isLeft, const QString &text)
{
    MessageContentLabel *messageContentLabel = new MessageContentLabel(isLeft, text);
    return messageContentLabel;
}

QWidget *MessageItem::makeImageMessageItem()
{
    QWidget *contentWidget = new QWidget();
    return contentWidget;
}

QWidget *MessageItem::makeFileMessageItem()
{
    QWidget *contentWidget = new QWidget();
    return contentWidget;
}

QWidget *MessageItem::makeSpeechMessageItem()
{
    QWidget *contentWidget = new QWidget();
    return contentWidget;
}

///
/// \brief MessageContentLabel::MessageContentLabel 构造消息正文的展示区域
/// \param text 文本消息正文
/// \param isLeft 判断是否是左侧消息的标志位
///
MessageContentLabel::MessageContentLabel(bool isLeft, const QString &text)
    : isLeft(isLeft)
{
    QFont font;
    font.setFamily("微软雅黑");
    font.setPixelSize(16);

    this->label = new QLabel(this);
    this->label->setText(text);
    this->label->setFont(font);
    this->label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    this->label->setWordWrap(true);
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QString thisLabelStyle = "QLabel { padding : 0px 10px; line-height : 1.2; background-color : transparent; }"; // padding顺序: 行, 列；1.2是系数
    this->label->setStyleSheet(thisLabelStyle);
}

///
/// \brief MessageContentLabel::paintEvent 手动绘制文本消息正文展示区背景气泡
/// \param event 事件发起者
/// \remarks 关于文本消息正文展示区的设计：
/// 1. 文本消息正文展示区最大宽度为父窗口宽度的60%, 当文字总宽度大于该宽度时要换行
/// 2. 宽度 = min(文字总宽度, 父窗口宽度的60%) + 左右padding(20*2)
/// 3. 高度 = [ (文字总宽度 / 单行宽度)(向上取整) ] * (line-height) * thisLabel字符高度 + 上下padding
/// 4. 根据宽高绘制圆角矩形和三角
///
void MessageContentLabel::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event); // 明确标记未使用的参数

    // 获取父元素窗体
    QObject *object = this->parent();
    if (!object->isWidgetType()) {
        return ;
    }
    QWidget *parent = dynamic_cast<QWidget *>(object);

    // 计算当前文本总宽度
    QFontMetrics metrics(this->label->font());
    int textTotalWidth = metrics.horizontalAdvance(this->label->text());

    // 计算单行最大宽度(文字宽度+左右padding)
    int lineMaxWidth = parent->width() * 0.6;

    // 计算行数
    int hPadding = 20 * 2;
    int rows = (textTotalWidth / (lineMaxWidth - hPadding)) + 1;

    // 计算文本展示区所需宽度
    int width = rows == 1 ? textTotalWidth + hPadding : lineMaxWidth;

    // 计算文本展示区所需高度
    int vPadding = 10 * 2;
    double lineHeightFactor = 1.2;
    int height = rows * (this->label->font().pixelSize() * lineHeightFactor) + vPadding;

    // 绘制圆角矩形和三角箭头
    QPainter painter(this);
    QPainterPath path;
    painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿
    if (isLeft) {
        // 画笔画刷
        painter.setPen(QPen(QColor(255, 255, 255)));
        painter.setBrush(QBrush(QColor(255, 255, 255)));

        // 圆角矩形
        QPoint leftTopPos(10, 0); // 左上角坐标
        painter.drawRoundedRect(leftTopPos.x(), leftTopPos.y(), width, height, 10, 10);

        // 三角箭头
        path.moveTo(leftTopPos.x(), leftTopPos.y() + 15);
        path.lineTo(leftTopPos.x() - 10, leftTopPos.y() + 20);
        path.lineTo(leftTopPos.x(), leftTopPos.y() + 25);
        path.closeSubpath();
        painter.drawPath(path);

        this->label->setGeometry(leftTopPos.x(), leftTopPos.y(), width, height);
    } else {
        // 画笔画刷
        painter.setPen(QPen(QColor(137, 217, 97)));
        painter.setBrush(QColor(137, 217, 97));

        // 圆角矩形
        QPoint leftTopPos(this->width() - width - 10, 0); // 左上角坐标
        painter.drawRoundedRect(leftTopPos.x(), leftTopPos.y(), width, height, 10, 10);

        // 三角箭头
        QPoint rightTopPos(this->width() - 10, 0);
        path.moveTo(rightTopPos.x(), rightTopPos.y() + 15);
        path.moveTo(rightTopPos.x() + 10, rightTopPos.y() + 20);
        path.moveTo(rightTopPos.x(), rightTopPos.y() + 25);
        path.closeSubpath();
        painter.drawPath(path);

        this->label->setGeometry(leftTopPos.x(), leftTopPos.y(), width, height);
    }

    // 重新设置父元素高度，确保能够完整显示消息以及名字和时间
    parent->setFixedHeight(height + 50);
}
















